#include "include.h"

struct w800_dev *tmp_w800dev;

static netdev_tx_t w800_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct w800_dev *w800dev;
	/*1)使用netif_stop_queue()来阻止上层向网络设备驱动层发送数据包*/
	netif_stop_queue(dev);
	w800dev = tmp_w800dev;
	w800dev->skb = skb;
	complete(&w800dev->bh_done);
	return 0;
}

static int w800_bh(void *arg)
{
	unsigned int timeout;
	struct w800_dev *w800dev;
	struct sk_buff *skb;
	int len;
	struct spi_transfer *spi_t;
	char *_rx_buf, *_tx_buf, *tmp, skb_tmp[3];
	spi_t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
	spi_t->speed_hz = 50000000;
	spi_t->rx_buf = kzalloc(100, GFP_KERNEL);
	spi_t->tx_buf = kzalloc(100, GFP_KERNEL);
	_rx_buf = (char *)(spi_t->rx_buf);
	_tx_buf = (char *)(spi_t->tx_buf);
	w800dev = arg;

	while (1)
	{
		reinit_completion(&w800dev->bh_done);
		timeout = wait_for_completion_timeout(&w800dev->bh_done, msecs_to_jiffies(5000));

		if (timeout)
		{
			// 向单片机发送数据帧
			if (w800dev->skb == NULL)
			{
				printk("w800dev->skb==NULL");
				continue;
			}
			skb = w800dev->skb;

			/**
			 * 检查w80x的下发数据接口是否繁忙 个人认为这样的两次检查会降低性能,但是又不得不这样做
			 * 繁忙主要是因为hspi在上传数据到主机,如果可以在上传数据到主机的时候做个全局变量的标志位
			 * 通过检查这个标志位来判断是否处于忙碌状态可以有效提升性能
			 */
			spi_t->len = 3;
			_tx_buf[0] = Read_reg(TX_BUFF_AVAIL); // 读取03寄存器
			_tx_buf[1] = 0;
			_tx_buf[2] = 0;
			w800_spiex(w800dev, spi_t);
			if (!(_rx_buf[1] & 0x01))
			{
				mdelay(1);
				spi_t->len = 3;
				_tx_buf[0] = Read_reg(TX_BUFF_AVAIL);
				_tx_buf[1] = 0;
				_tx_buf[2] = 0;
				w800_spiex(w800dev, spi_t);
				if (!(_rx_buf[1] & 0x01))
				{
					printk("spi_net error, w800 busy!");
					continue;
				}
			}

			/**
			 * 将skb的data数据段借来用 同时向上吃3个字节
			*/
			spi_t->tx_buf = skb->data - 3;
			tmp = (char *)spi_t->tx_buf;

			// 临时保存数据区前三个数据
			// skb_tmp[0] = tmp[0];
			// skb_tmp[1] = tmp[1];
			// skb_tmp[2] = tmp[2];

			/**
			 * 配置交换参数, 向hspi数据端口1写数据
			*/
			tmp[0] = Write_reg(DAT_PORT1);
			tmp[1] = skb->len & 0xff;
			tmp[2] = (skb->len >> 8) & 0xff;
			len = skb->len + 2;
			if (len % 4 != 0)
			{
				len = (len / 4 + 1) * 4;
			}
			spi_t->len = len + 1;
			w800_spiex(w800dev, spi_t); // 启动SPI交换

			// 将临时保存的数据写回skb->data之前
			// tmp[0] = skb_tmp[0];
			// tmp[1] = skb_tmp[1];
			// tmp[2] = skb_tmp[2];

			spi_t->tx_buf = _tx_buf; // 恢复发送缓存区地址

			w800dev->w_net->stats.tx_packets++;
			w800dev->w_net->stats.tx_bytes += skb->len;

			// 释放发送的sk_buff缓存区
			dev_kfree_skb(skb);
		}
		netif_wake_queue(w800dev->w_net);
	}
	kfree(spi_t->tx_buf);
	kfree(spi_t->rx_buf);
	kfree(spi_t);
	return 0;
}

static int w800_open(struct net_device *dev)
{
	return 0;
}

static int w800_close(struct net_device *dev)
{
	return 0;
}

static const struct net_device_ops w800_netdev_ops = {
	.ndo_open = w800_open,
	.ndo_stop = w800_close,
	.ndo_start_xmit = w800_start_xmit,
};

int get_mac(struct w800_dev *w800dev, char *mac)
{
	struct spi_transfer *spi_t;
	char *_rx_buf, *_tx_buf;
	char i;

	spi_t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
	spi_t->speed_hz = 50000000;
	spi_t->rx_buf = kzalloc(100, GFP_KERNEL);
	spi_t->tx_buf = kzalloc(100, GFP_KERNEL);
	_rx_buf = (char *)(spi_t->rx_buf);
	_tx_buf = (char *)(spi_t->tx_buf);

	// 发送获取mac地址
	_tx_buf[0] = Write_reg(DN_CMD_PORT1);
	_tx_buf[1] = 1;
	_tx_buf[2] = 0;
	_tx_buf[3] = 0;
	_tx_buf[4] = 0;
	spi_t->len = 9;
	w800_spiex(w800dev, spi_t); // 启动SPI交换
	w800_spiex(w800dev, spi_t); // 启动SPI交换
	w800_spiex(w800dev, spi_t); // 启动SPI交换

	for (i = 0; i < 16; i++)
	{
		msleep(100);
		_tx_buf[0] = Read_reg(DAT_PORT1);
		spi_t->len = 13;
		w800_spiex(w800dev, spi_t); // 启动SPI交换
		if (_rx_buf[1] == 0xa5 && _rx_buf[2] == 0xa5 &&
			_rx_buf[3] == 0x0a && _rx_buf[4] == 0x00)
		{
			printk("macaddr %02x:%02x:%02x:%02x:%02x:%02x",
				   _rx_buf[5], _rx_buf[6], _rx_buf[7], _rx_buf[8], _rx_buf[9], _rx_buf[10]);
			mac[0] = _rx_buf[5];
			mac[1] = _rx_buf[6];
			mac[2] = _rx_buf[7];
			mac[3] = _rx_buf[8];
			mac[4] = _rx_buf[9];
			mac[5] = _rx_buf[10];
			printk("w800 is okk");
			break;
		}
	}

	// 如果wifi没有自动连接  就给他配置wifi与密码   然后自动连接
	// if(_rx_buf[7]==0)
	{
		_tx_buf[0] = Write_reg(DN_CMD_PORT1);
		_tx_buf[1] = 5;
		_tx_buf[2] = 0;
		_tx_buf[3] = 8;
		_tx_buf[4] = 0;
		sprintf(_tx_buf + 5, "jtjtjt11"); // 发送wifi  password
		spi_t->len = 17;
		w800_spiex(w800dev, spi_t); // 启动SPI交换

		msleep(50);

		_tx_buf[0] = Write_reg(DN_CMD_PORT1);
		_tx_buf[1] = 4;
		_tx_buf[2] = 0;
		_tx_buf[3] = 3;
		_tx_buf[4] = 0;
		sprintf(_tx_buf + 5, "CYY"); // 发送wifi  ssid
		spi_t->len = 13;
		w800_spiex(w800dev, spi_t); // 启动SPI交换

		msleep(50);

		_tx_buf[0] = Write_reg(DN_CMD_PORT1);
		_tx_buf[1] = 10;
		_tx_buf[2] = 0;
		_tx_buf[3] = 8;
		_tx_buf[4] = 0;
		_tx_buf[5] = 1; // 发送自动连接模式
		spi_t->len = 9;
		w800_spiex(w800dev, spi_t); // 启动SPI交换

		msleep(50);

		_tx_buf[0] = Write_reg(DN_CMD_PORT1);
		_tx_buf[1] = 8; // 发送连接命令
		_tx_buf[2] = 0;
		_tx_buf[3] = 0;
		_tx_buf[4] = 0;
		spi_t->len = 9;
		w800_spiex(w800dev, spi_t); // 启动SPI交换
	}

	msleep(50);
	_tx_buf[0] = Write_reg(DN_CMD_PORT1);
	_tx_buf[1] = 0; // 发送连接命令
	_tx_buf[2] = 0;
	_tx_buf[3] = 0;
	_tx_buf[4] = 0;
	spi_t->len = 9;
	w800_spiex(w800dev, spi_t); // 启动SPI交换

	return 0;
}

void spinet_init(struct w800_dev *w800dev)
{
	struct net_device *w800_net;
	struct task_struct *bh_thread;
	int ret;

	tmp_w800dev = w800dev;

	w800dev->w_net = alloc_netdev_mqs(sizeof(struct net_device), "eth0", NET_NAME_UNKNOWN, ether_setup, 1, 1);
	w800_net = w800dev->w_net;
	w800_net->private_sector = w800dev;

	w800_net->netdev_ops = &w800_netdev_ops;
	w800_net->mtu = 1500;
	// w800_net->dev_addr[0] = 0x28;
	// w800_net->dev_addr[1] = 0x6d;
	// w800_net->dev_addr[2] = 0xcd;
	// w800_net->dev_addr[3] = 0xce;
	// w800_net->dev_addr[4] = 0x4b;
	// w800_net->dev_addr[5] = 0x7d;

	ret = get_mac(w800dev, w800_net->dev_addr);
	if (ret)
		return;

	w800_net->flags |= IFF_RUNNING;
	w800_net->features = 0;

	register_netdev(w800_net);

	init_completion(&w800dev->bh_done);

	bh_thread = kthread_create(w800_bh, w800dev, "w800_bh");
	w800dev->bh_th = bh_thread;
	wake_up_process(bh_thread);
}

void rm_spinet_init(struct w800_dev *w800dev)
{
	struct net_device *w800_net;
	w800_net = w800dev->w_net;
	tmp_w800dev = NULL;
	unregister_netdev(w800_net);
}